/* ************************************************************************ */
/*                                                                          */
/*  Copyright (c)2005 Russell Weir | damonsbane _at_ gmail                  */
/*                                                                          */
/* This library is free software; you can redistribute it and/or            */
/* modify it under the terms of the GNU Lesser General Public               */
/* License as published by the Free Software Foundation; either             */
/* version 3.0 of the License, or (at your option) any later version.       */
/*                                                                          */
/* This library is distributed in the hope that it will be useful,          */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of           */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        */
/* Lesser General Public License or the LICENSE file for more details.      */
/*                                                                          */
/* ************************************************************************ */

package tzparser;
import altdate.TimeSpecification;
import altdate.DaySpecification;

/*
# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
Zone America/Miquelon	-3:44:40 -	LMT	1911 May 15	# St Pierre
			-4:00	-	AST	1980 May
			-3:00	-	PMST	1987 # Pierre & Miquelon Time
			-3:00	Canada	PM%sT
*/




class ParseZone {

	public static function parse(line : String, fi : neko.io.FileInput) : Zone {
		// 1     2                   3        4          5       [6    7  8   9]
		//Zone  NAME                GMTOFF  RULES/SAVE  FORMAT  [UNTILYEAR [MONTH [DAY [TIME]]]]
		//Zone America/Puerto_Rico -4:24:25    -	LMT	1899 Mar 28 12:00    # San Juan
		//	-4:00	-	AST	1942 May  3
		//	-4:00	US	A%sT	1946
		//	-4:00	-	AST
		var matched = parseLine(line);

		if(matched.length == 0 || matched[0] != "Zone") {
			trace(line + " NOT ZONE LINE");
			return null;
		}
		//trace(matched[0] + " " + matched[1] + " " + Parser.parseOffset(matched[2]));

		matched.shift();

		// all offsets will come back as WALL, but are in fact seconds off GMT, for at least the first line
		var hasContinue : Bool = true;
		var first : Bool = true;
		var zone = new Zone(matched.shift());

		while(hasContinue) {
			var chainName : String;
			var offset : TimeSpecification;
			var rules : String;
			var format : ZoneFormat;
			var until : Until;

			if(!first) {
				// continuation line skips field 1 and 2
				line = StringTools.trim(fi.readLine());
				matched = parseLine(line);
				if(matched == null)
					continue;
			}
			//trace(line);
			until = parseUntil(matched);
			if(until == null) {
				hasContinue = false;
				until = new Until();
			}

			// GMTOFF
			offset = TimeSpecification.parse(matched[0]);

			// RULES/SAVE
			rules = matched[1];

			// FORMAT
			format = ZoneFormat.parse(matched[2]);

			if(!first) {
				// previous rule ends at beginning of this new rule
			}

			zone.addRule(new ZoneRule(offset,rules,format,until));
			//trace(rule);
			first = false;
		}

		return zone;
	}

	static function parseLine(line:String) : Array<String> {
		// ~ /^Zone\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)(\s+([0-9]+(\s+.*)?))?$/
		var idx = line.lastIndexOf("#");
		if(idx >= 0) {
			line = line.substr(0,idx);
		}
		line = StringTools.trim(line);
		var r = ~/\s+/g;
		line = r.replace(line," ");
		line = StringTools.trim(line);
		if(line.length == 0)
			return null;
		var parts = line.split(" ");
		var last = parts.length - 1;
		if(last < 0)
			return null;

		parts[last] = StringTools.trim(parts[last]);

		var rv = new Array<String>();
		var inQuote : Bool = false;
		var qs : StringBuf;
		for(i in parts) {
			if(inQuote) {
				if(i.charAt(i.length-1) == '"') {
					inQuote = false;
					qs.add(i.substr(0,i.length-1));
					rv.push(qs.toString());
					continue;
				}
				qs.add(i);
				continue;
			}
			if(i.charAt(0) == '"') {
				inQuote = true;
				qs=new StringBuf();
				qs.add(i.substr(1));
				continue;
			}
			rv.push(i);
		}
		return rv;
	}

	static function parseUntil(r : Array<String>) : Null<Until> {
		if(r.length < 4)
			return null;
		var until = new Until();
		until.year = Std.parseInt(r[3]);

		if(r.length > 4) {
			until.month = altdate.Tools.monthToInt(r[4]);
			if(r.length > 5) {
				until.onDay = DaySpecification.parse(r[5]);
				if(r.length > 6)
					until.atTime = TimeSpecification.parse(r[6]);
			}
		}

		return until;
	}
}

